// ignore_for_file: unused_local_variable, avoid_function_literals_in_foreach_calls

import 'dart:async';
import 'dart:io';
import 'dart:typed_data';

import 'package:dmz/tools/blue/blue_business.dart';
import 'package:dmz/tools/blue/blue_config.dart';
import 'package:dmz/tools/blue/blue_tools.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';

// import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:permission_handler/permission_handler.dart';

///蓝牙单例
class EMIBlueMangered {
  factory EMIBlueMangered() => _instance;

  static final EMIBlueMangered _instance = EMIBlueMangered._internal();

  ///扫描结果
  List<ScanResult> deviceList = [];

  ///设备登录时间
  List<int> bleLoginDete = [];

  ///已连接设备
  List<String> contnetNames = [];

  ///写入监听
  Map<String, BluetoothCharacteristic> writes = {};

  ///读取监听
  Map<String, StreamSubscription<List<int>>> reds = {};

  ///链接监听
  Map<String, StreamSubscription<BluetoothConnectionState>> contents = {};

  ///蓝发送数据回调
  Map<String, Function(String content)?> callbacks = {};

  Map<String, BluetoothDevice> contentDevices = {};

  EMIBlueMangered._internal() {
    init();
  }
  init() {}

  ///蓝牙检查
  blueExamine() async {
    var permissions = FlutterBluePlus.adapterStateNow;

    switch (permissions) {
      case BluetoothAdapterState.unauthorized:
        return await requestBlePermissions();
      case BluetoothAdapterState.unavailable:
        return await FlutterBluePlus.turnOn();
      // return false;
      case BluetoothAdapterState.off:
        return await FlutterBluePlus.turnOn();
      // return false;
      case BluetoothAdapterState.on:
        return true;
      default:
        return await requestBlePermissions();
    }
  }

  ///请求权限
  Future<bool> requestBlePermissions() async {
    var isLocationGranted = await Permission.locationWhenInUse.request();
    debugPrint('权限1 checkBlePermissions, isLocationGranted=$isLocationGranted');

    var isBleGranted = await Permission.bluetooth.request();
    debugPrint('权限2 checkBlePermissions, isBleGranted=$isBleGranted');

    var isBleScanGranted = await Permission.bluetoothScan.request();
    debugPrint('权限3 checkBlePermissions, isBleScanGranted=$isBleScanGranted');
    //
    var isBleConnectGranted = await Permission.bluetoothConnect.request();
    debugPrint(
        '权限4 checkBlePermissions, isBleConnectGranted=$isBleConnectGranted');
    //
    var isBleAdvertiseGranted = await Permission.bluetoothAdvertise.request();
    debugPrint(
        '权限5 checkBlePermissions, isBleAdvertiseGranted=$isBleAdvertiseGranted');

    if (Platform.isIOS) {
      return isBleGranted == PermissionStatus.granted ||
          isBleGranted == PermissionStatus.permanentlyDenied;
    } else {
      return isLocationGranted == PermissionStatus.granted &&
          isBleScanGranted == PermissionStatus.granted &&
          isBleConnectGranted == PermissionStatus.granted &&
          isBleAdvertiseGranted == PermissionStatus.granted;
    }
  }

  stopScan() async {
    await FlutterBluePlus.stopScan();
  }

  ///获取扫描到的设备
  Future<void> getSanDeviceList(Function(List<ScanResult>) callBack,
      {Function(bool)? finish, String? snCode, String? name}) async {
    var type = await blueExamine();
    if (!type) {
      return;
    }
    if (FlutterBluePlus.isScanningNow) await stopScan();
    debugPrint("扫描 开始 000");
    List devicesed = [];
    deviceList = [];
    var subscription = FlutterBluePlus.onScanResults.listen(
      (results) {
        List<ScanResult> deviceListed = [];

        for (var element in results) {
          var device = element.device;
          // debugPrint("扫描中00 ---- ${device.advName} ---${device.remoteId.str} ");
          if (device.advName.isNotEmpty &&
              element.advertisementData.serviceUuids.isNotEmpty) {
            // debugPrint(
            //     "扫描中11 ---- ${device.advName} ${element.advertisementData.serviceUuids.first.str}");
            String data1 = element.advertisementData.serviceUuids.first.str;
            String result = EMIBlueTool.scanAnalysis(data1);
            if (result.contains('KRen') &&
                !devicesed.contains(device.advName)) {
              debugPrint("扫描中222 ---- ${device.advName}");
              devicesed.add(device.advName);
              deviceList.add(element);
            }
          }
        }
        callBack(deviceList);
      },
      onError: (e) => print(e),
    );
    FlutterBluePlus.cancelWhenScanComplete(subscription);
    await FlutterBluePlus.adapterState
        .where((val) => val == BluetoothAdapterState.on)
        .first;
    await FlutterBluePlus.startScan(
            withServices: [], // match any of the specified services
            withNames: [], // *or* any of the specified names
            timeout: const Duration(seconds: 15))
        .then((value) {
      debugPrint("扫描 完毕 ----111");
    });

    await FlutterBluePlus.isScanning.where((val) => val == false).first;
    if (finish != null) finish(deviceList.isNotEmpty);
  }

  ///扫描连接设备
  Future<void> scanAndContentDevice(
      String snCond, String remoteId, Function(bool) callBack) async {
    var type = await blueExamine();
    if (!type) return;
    // stopScan();
    debugPrint("蓝牙 直接连接 -- $snCond $remoteId");
    // E7D6E57F-6E40-6EE9-32DD-C178BA606682
    BluetoothDevice blueDevice = BluetoothDevice.fromId(remoteId);
    debugPrint("蓝牙 直接连接 -- ${blueDevice.isConnected} $remoteId");

    var subscriptioned = blueDevice.connectionState
        .listen((BluetoothConnectionState state) async {
      debugPrint("蓝牙状态 $state");
      if (state == BluetoothConnectionState.disconnected) {
        contnetNames.remove(snCond);
        contentDevices.remove(snCond);
        callBack(false);
      }
      if (state == BluetoothConnectionState.connected) {
        debugPrint('蓝牙 订阅特征000 --- 11111');
        discoverServicesed(snCond, blueDevice, EMIServiceUUID.serviceRedUUID,
            EMIServiceUUID.serviceUUID);
        contentDevices[snCond] = blueDevice;
        contnetNames.add(snCond);

        callBack(true);
      }
    });

    try {
      await blueDevice.disconnect();
      debugPrint("蓝牙 直接连接 0");
      await blueDevice.connect();
      debugPrint("蓝牙 直接连接 1");
    } catch (e) {
      debugPrint("蓝牙 直接连接 error -- $e");
      await blueDevice.connect();
    }

    contents[snCond] = subscriptioned;
  }

  ///扫描后连接设备
  void contentDeviceWithSN(
      String snCond, String mac, Function(bool) callBack) async {
    disContenWidhSNCode(snCond);
    var subscription = FlutterBluePlus.onScanResults.listen(
      (results) {
        deviceList = results;
        for (ScanResult device in results) {
          if (device.device.advName
              .contains(snCond.substring(snCond.length - 4))) {
            ///停止扫描
            stopScan();
            debugPrint('蓝牙 扫描连接 ---${device.device.remoteId}');
            contentCallback(device, snCond, callBack);
          }
        }
      },
      onError: (e) => print(e),
    );
    Future.delayed(const Duration(seconds: 10), () {
      bool contentName = false;
      deviceList.forEach((element) {
        if (element.device.advName
            .contains(snCond.substring(snCond.length - 4))) {
          contentName = true;
        }
      });
      if (!contentName) {
        debugPrint('蓝牙 直接连接  ');
        scanAndContentDevice(snCond, mac, callBack);
      }
    });

    FlutterBluePlus.cancelWhenScanComplete(subscription);
    await FlutterBluePlus.adapterState
        .where((val) => val == BluetoothAdapterState.on)
        .first;
    await FlutterBluePlus.startScan(
            withServices: [], // match any of the specified services
            withNames: [], // *or* any of the specified names
            timeout: const Duration(seconds: 5))
        .then((value) {
      debugPrint("扫描 完毕 ----111");
    });

    await FlutterBluePlus.isScanning.where((val) => val == false).first;
  }

  ///连接设备
  Future<void> contentCallback(
      ScanResult result, String snCond, Function(bool) callBack) async {
    var type = await blueExamine();
    if (!type) return;
    stopScan();
    if (contents[snCond] != null) {
      contents[snCond]?.cancel();
      contents.remove(snCond);
    }
    // listen for disconnection
    var subscription = result.device.connectionState
        .listen((BluetoothConnectionState state) async {
      if (state == BluetoothConnectionState.disconnected) {
        contentDevices.remove(snCond);
        contnetNames.remove(snCond);
        contents[snCond]?.cancel();
        contents.remove(snCond);
        callBack(false);
      }
      if (state == BluetoothConnectionState.connected) {
        debugPrint('蓝牙 订阅特征000 --- 22222');
        discoverServicesed(snCond, result.device, EMIServiceUUID.serviceRedUUID,
            EMIServiceUUID.serviceUUID);
        contentDevices[snCond] = result.device;
        contnetNames.add(snCond);
        callBack(true);
      }
    });

    try {
      await result.device.disconnect();
      await result.device.connect();
    } catch (e) {
      await result.device.connect();
    }

    contents[snCond] = subscription;
  }

  ///断开设备
  void disContenWidhSNCode(String snCode) async {
    contentDevices[snCode]?.disconnect();
    reds[snCode]?.cancel();
    contents[snCode]?.cancel();
    contents.remove(snCode);
  }

  ///发送数据
  sendData(String snCode,
      {EMIBlueACT? action,
      List<int>? otherData,
      int? otherSetData,
      Function(String content)? callback}) async {
    var type = await blueExamine();
    debugPrint('蓝牙 写入数据 ---000 $type $action otherSetData--$otherData');
    if (!type) return;

    List<int> snedData = otherData ??
        EMIBlueBusiness.getWriteData(action!, otherData: otherSetData);
    var key = EMIBlueTool.getCallBackKey(snedData);
    debugPrint('蓝牙回调00000 ---$callback $key $callbacks');
    if (callback != null) {
      callbacks[key] = callback;
      debugPrint('蓝牙回调111 ---$callback $key $callbacks');
    }
    debugPrint(
        '蓝牙 写入数据1 ---${EMIBlueTool.deviceDataAnalysis(snedData)} --- $snedData');
    var dataLong = snedData[1];
    List<int> dataed = List<int>.from(snedData);
    dataed.replaceRange(1, 2, [dataLong + 1]);
    //crc 校验
    Uint8List data = Uint8List.fromList(dataed);
    int crc = CRC8.calculateCRC(data);
    dataed.add(crc);
    debugPrint('蓝牙 写入数据2 ---crc $crc $dataed --- $snedData');
    writes[snCode]?.write(dataed);
  }

  ///获取订阅特征
  discoverServicesed(String snCode, BluetoothDevice device,
      String characteristicId, String serviceId) async {
    debugPrint('蓝牙 订阅特征000 --- ');
    device.discoverServices().then((services) {
      for (BluetoothService service in services) {
        if (service.uuid == Guid(EMIServiceUUID.serviceUUID)) {
          service.characteristics.forEach((characteristic) async {
            if (reds[snCode] != null) {
              debugPrint('蓝牙 订阅特征222 --- ');
              reds[snCode]?.cancel();
              reds.remove(snCode);
              writes.remove(snCode);
            }
            if (characteristic.uuid == Guid(EMIServiceUUID.serviceRedUUID)) {
              // 监听特征的数据变化事件
              debugPrint('蓝牙 订阅特征 3333  --- ');
              var data = characteristic.onValueReceived.listen((value) {
                debugPrint('蓝牙 订阅特征 数据返回  --- ');
                EMIBlueBusiness.didToCharacteristic(snCode, value);
              });
              device.cancelWhenDisconnected(data);
              // 订阅特征的数据通知
              await characteristic.setNotifyValue(true);

              reds[snCode] = data;
            }
            if (characteristic.uuid == Guid(EMIServiceUUID.serviceWriteUUID)) {
              writes[snCode] = characteristic;
              // // 订阅特征的数据通知
              // await characteristic.setNotifyValue(true);

              // // 监听特征的数据变化事件
              // characteristic.onValueReceived.listen((value) {
              //   print('写入监听 data: $value');
              // });
            }
          });
        }
      }
    });
  }

  Future<bool> requestBluePermission({first = false}) async {
    var status = await Permission.bluetooth.status;
    if (status.isDenied && !first) {
      await Future.delayed(Duration.zero);
      var dataed = await Permission.bluetooth.request();
      return dataed.isGranted;
    } else {
      return status.isGranted;
    }
  }
}
